﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Walson.Scientific.Random
{
    /// <summary>
    /// 产生一个服从N(μ,σ*σ)的正态分布随机数
    /// </summary>
    public class GaussianDistribution
    {
        int iset;
        double gset;
        System.Random r1, r2;

        /// <summary>
        /// 产生一个服从正态分布的随机数
        /// </summary>
        public GaussianDistribution()
        {
            r1 = new System.Random(Guid.NewGuid().GetHashCode());
            r2 = new System.Random(Guid.NewGuid().GetHashCode());
            iset = 0;
        }
        
        /// <summary>
        /// 产生一个服从N(μ,σ*σ)的正态分布随机数
        /// </summary>
        /// <param name="u">期望μ</param>
        /// <param name="sigma">标准差σ</param>
        /// <returns>随机数</returns>
        public double NextGaussian(double u, double sigma)
        {
            double fac, rsq, v1, v2,result;

            if (iset == 0)
            {
                do
                {
                    v1 = 2.0 * r1.NextDouble() - 1.0;
                    v2 = 2.0 * r2.NextDouble() - 1.0;
                    rsq = v1 * v1 + v2 * v2;
                } while (rsq >= 1.0 || rsq == 0.0);

                fac = Math.Sqrt(-2.0 * Math.Log(rsq) / rsq);
                gset = v1 * fac;
                iset = 1;
                result= v2 * fac;
            }
            else
            {
                iset = 0;
                result= gset;
            }

            result = result * sigma * sigma + u;

            return result;
        }

    }

    /// <summary>
    /// 产生一个服从均匀分布的随机数
    /// </summary>
    public class AverageDistribution
    {
        /// <summary>
        /// 产生一个服从均匀分布的随机数
        /// </summary>
        /// <param name="min">均匀分布的下限</param>
        /// <param name="max">均匀分布的上限</param>
        public AverageDistribution()
        {
        }

        /// <summary>
        /// 产生一个服从均匀分布的随机数
        /// </summary>
        /// <returns>产生的随机数</returns>
        public double NextAverage(double min, double max)
        {
            double result = 0;
            System.Random rand = new System.Random(Guid.NewGuid().GetHashCode());
            result = rand.NextDouble() * (max - min) + min;
            return result;
        }
    }

    /// <summary>
    /// 产生一个服从参数为 lamda 的指数分布的随机数
    /// </summary>
    public class ExpDistribution
    {
        /// <summary>
        /// 产生一个服从参数为 lamda 的指数分布的随机数
        /// </summary>
        
        public ExpDistribution()
        {
        }

        /// <summary>
        /// 指数分布随机数
        /// </summary>
        /// <param name="lamda">参数</param>
        /// <returns>随机数</returns>
        public double NextExp(double lamda)
        {
            System.Random rand = new System.Random(Guid.NewGuid().GetHashCode());
            double p;
            double temp;
            if (lamda != 0)
                temp = 1 / lamda;
            else
                throw new System.InvalidOperationException("除数不能为零！不能产生参数为零的指数分布！");
            double randres;
            while (true) //用于产生随机的密度，保证比参数λ小
            {
                p = rand.NextDouble();
                if (p < lamda)
                    break;
            }
            randres = -temp * Math.Log(temp * p, Math.E);
            return randres;
        }
    }

    /// <summary>
    /// 产生一个服从参数为 lamda 的负指数分布的随机数
    /// </summary>
    public class NExpDistribution
    {
        /// <summary>
        /// 产生一个服从负指数分布的随机数
        /// </summary>
        /// <param name="lamda">lamda</param>
        public NExpDistribution()
        {
        }

        /// <summary>
        /// 产生一个服从参数为 lamda 的负指数分布的随机数
        /// </summary>
        /// <param name="lamda">参数</param>
        /// <returns>随机数</returns>
        public double NextNExp(double lamda)
        {
            System.Random ran = new System.Random(Guid.NewGuid().GetHashCode());
            double dec = ran.NextDouble();
            while (dec == 0)
                dec = ran.NextDouble();
            return -Math.Log(dec) / lamda;
        }
    }

    /// <summary>
    /// 产生服从泊松分布的随机数
    /// </summary>
    public class PoisonDistribution
    {
        /// <summary>
        /// 产生服从泊松分布的随机数
        /// </summary>
        public PoisonDistribution()
        {
        }

        /// <summary>
        /// 产生一个服从参数为 lamda、时间为 time 的泊松分布的随机数
        /// </summary>
        /// <param name="lam">参数</param>
        /// <param name="time">时间</param>
        /// <returns></returns>
        public double poisson(double lamda,double time)
        {
            int count = 0;
            NExpDistribution ngtIndex = new NExpDistribution();
            while (true)
            {
                time -= ngtIndex.NextNExp(lamda);
                if (time > 0)
                    count++;
                else
                    break;
            }
            return count;
        }
    }
}
